module ieee754_plus
(
    //data input
    input      [31:0] a,
    input      [31:0] b,
    //data output
    output  [31:0] c,

    //ctrl
    input                   opCode      ,    
    output  reg             err  
);

wire sign_a=a[31];
wire sign_b=b[31];

// 指数域
wire [7:0] exp_a_raw = a[30:23];
wire [7:0] exp_b_raw = b[30:23];
// 判断非规格化数（指数为0）
wire a_denorm = (exp_a_raw == 8'd0);
wire b_denorm = (exp_b_raw == 8'd0);

// 尾数处理：非规格化数隐含0，规格化数隐含1
wire [23:0] abs_a = a_denorm ? {1'b0, a[22:0]} : {1'b1, a[22:0]};
wire [23:0] abs_b = b_denorm ? {1'b0, b[22:0]} : {1'b1, b[22:0]};

 // 指数调整：非规格化数实际指数为-126（按指数=1处理）
wire [7:0] exp_a = (a_denorm ? 8'd1 : exp_a_raw);
wire [7:0] exp_b = (b_denorm ? 8'd1 : exp_b_raw);

reg sign_c;
reg [7:0] exp_c;
reg [23:0] abs_c;

//----------------------------------------------
wire                diff_sign   ;
reg     [7:0]       diff_exp_1  ;
reg     [7:0]       exp_both    ;
reg     [7:0]       exp_c_p   ;
reg     [23:0]      abs_a_2   ;
reg     [23:0]      abs_b_2   ;
reg     [24:0]      abs_c_2   ;

//----------------- sign  -------------------------------------
assign diff_sign = sign_a ^ sign_b;

always @(*)
begin
    if (opCode ^ diff_sign) //different sign
    begin
        if(abs_a_2 > abs_b_2)   //abs diff
            sign_c = sign_a;
        else
        begin
            if (~opCode)    //plus
                sign_c = sign_b;
            else //trime
                sign_c = ~sign_a;
        end 
    end 

    else    //same sign
        sign_c = sign_a;
end

//-------------------- abs ----------------------------------
always @(*)
begin
    if(exp_a > exp_b)
    begin
        diff_exp_1 = exp_a - exp_b; //指数差
        exp_both   = exp_a;
        abs_a_2  = abs_a;
        
        case(diff_exp_1)
            8'd1 :   abs_b_2 = {1'd0 , abs_b[23:1 ]};
            8'd2 :   abs_b_2 = {2'd0 , abs_b[23:2 ]};
            8'd3 :   abs_b_2 = {3'd0 , abs_b[23:3 ]};
            8'd4 :   abs_b_2 = {4'd0 , abs_b[23:4 ]};
            8'd5 :   abs_b_2 = {5'd0 , abs_b[23:5 ]};
            8'd6 :   abs_b_2 = {6'd0 , abs_b[23:6 ]};
            8'd7 :   abs_b_2 = {7'd0 , abs_b[23:7 ]};
            8'd8 :   abs_b_2 = {8'd0 , abs_b[23:8 ]};
            8'd9 :   abs_b_2 = {9'd0 , abs_b[23:9 ]};
            8'd10:   abs_b_2 = {10'd0, abs_b[23:10]};
            8'd11:   abs_b_2 = {11'd0, abs_b[23:11]};
            8'd12:   abs_b_2 = {12'd0, abs_b[23:12]};
            8'd13:   abs_b_2 = {13'd0, abs_b[23:13]};
            8'd14:   abs_b_2 = {14'd0, abs_b[23:14]};
            8'd15:   abs_b_2 = {15'd0, abs_b[23:15]};
            8'd16:   abs_b_2 = {16'd0, abs_b[23:16]};
            8'd17:   abs_b_2 = {17'd0, abs_b[23:17]};
            8'd18:   abs_b_2 = {18'd0, abs_b[23:18]};
            8'd19:   abs_b_2 = {19'd0, abs_b[23:19]};
            8'd20:   abs_b_2 = {20'd0, abs_b[23:20]};
            8'd21:   abs_b_2 = {21'd0, abs_b[23:21]};
            8'd22:   abs_b_2 = {22'd0, abs_b[23:22]};
            8'd23:   abs_b_2 = {23'd0, abs_b[23:23]};
            default: abs_b_2 = 24'd0;
        endcase
    end
    else
    begin
        diff_exp_1  = exp_b - exp_a;
        exp_both    = exp_b;
        abs_b_2   = abs_b;

        case(diff_exp_1)
            8'd0 :   abs_a_2 = abs_a[23:0];
            8'd1 :   abs_a_2 = {1'd0 , abs_a[23:1 ]};
            8'd2 :   abs_a_2 = {2'd0 , abs_a[23:2 ]};
            8'd3 :   abs_a_2 = {3'd0 , abs_a[23:3 ]};
            8'd4 :   abs_a_2 = {4'd0 , abs_a[23:4 ]};
            8'd5 :   abs_a_2 = {5'd0 , abs_a[23:5 ]};
            8'd6 :   abs_a_2 = {6'd0 , abs_a[23:6 ]};
            8'd7 :   abs_a_2 = {7'd0 , abs_a[23:7 ]};
            8'd8 :   abs_a_2 = {8'd0 , abs_a[23:8 ]};
            8'd9 :   abs_a_2 = {9'd0 , abs_a[23:9 ]};
            8'd10:   abs_a_2 = {10'd0, abs_a[23:10]};
            8'd11:   abs_a_2 = {11'd0, abs_a[23:11]};
            8'd12:   abs_a_2 = {12'd0, abs_a[23:12]};
            8'd13:   abs_a_2 = {13'd0, abs_a[23:13]};
            8'd14:   abs_a_2 = {14'd0, abs_a[23:14]};
            8'd15:   abs_a_2 = {15'd0, abs_a[23:15]};
            8'd16:   abs_a_2 = {16'd0, abs_a[23:16]};
            8'd17:   abs_a_2 = {17'd0, abs_a[23:17]};
            8'd18:   abs_a_2 = {18'd0, abs_a[23:18]};
            8'd19:   abs_a_2 = {19'd0, abs_a[23:19]};
            8'd20:   abs_a_2 = {20'd0, abs_a[23:20]};
            8'd21:   abs_a_2 = {21'd0, abs_a[23:21]};
            8'd22:   abs_a_2 = {22'd0, abs_a[23:22]};
            8'd23:   abs_a_2 = {23'd0, abs_a[23:23]};
            default: abs_a_2 = 24'd0;
        endcase
    end
end

always @(*)
begin
    if (opCode ^ diff_sign) //different sign
    begin
        if(abs_a_2 > abs_b_2)
            abs_c_2  = abs_a_2 - abs_b_2;  //(24-24 --> 24)
        else
            abs_c_2  = abs_b_2 - abs_a_2;
    end 
    else    //same sign
        abs_c_2  = abs_a_2 + abs_b_2;    //(24+24 ---> 25)
end

always @(*)
begin
    //------------
   if (abs_c_2[24])
    begin
        exp_c_p = exp_both + 8'd1;
        if (exp_c_p == 8'hFF || (exp_both == 8'hFF)) begin
            err = 1'b1;       
            exp_c = 8'hFF;    
            abs_c = 24'h000000;
        end else begin
            err = 1'b0;
            exp_c = exp_c_p;
            abs_c = abs_c_2[24:1];
        end
    end

    //------------
    else if(abs_c_2[23])
    begin
        err       = 1'b0;
        exp_c_p = exp_both;
        exp_c   = exp_c_p;
        abs_c   = abs_c_2[23:0];
    end

    //------------
    else if(abs_c_2[22])
    begin
        {err, exp_c_p} = exp_both - 8'd1;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[22:0],1'd0};
        end
    end

    //------------
    else if(abs_c_2[21])
    begin
        {err, exp_c_p} = exp_both - 8'd2;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[21:0],2'd0};
        end
    end

    //------------
    else if(abs_c_2[20])
    begin
        {err, exp_c_p} = exp_both - 8'd3;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[20:0],3'd0};
        end
    end

    //------------
    else if(abs_c_2[19])
    begin
        {err, exp_c_p} = exp_both - 8'd4;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[19:0],4'd0};
        end
    end

    //------------
    else if(abs_c_2[18])
    begin
        {err, exp_c_p} = exp_both - 8'd5;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[18:0],5'd0};
        end
    end

    //------------
    else if(abs_c_2[17])
    begin
        {err, exp_c_p} = exp_both - 8'd6;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[17:0],6'd0};
        end
    end

    //------------
    else if(abs_c_2[16])
    begin
        {err, exp_c_p} = exp_both - 8'd7;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[16:0],7'd0};
        end
    end

    //------------
    else if(abs_c_2[15])
    begin
        {err, exp_c_p} = exp_both - 8'd8;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[15:0],8'd0};
        end
    end

    //------------
    else if(abs_c_2[14])
    begin
        {err, exp_c_p} = exp_both - 8'd9;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[14:0],9'd0};
        end
    end

    //------------
    else if(abs_c_2[13])
    begin
        {err, exp_c_p} = exp_both - 8'd10;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[13:0],10'd0};
        end
    end

    //------------
    else if(abs_c_2[12])
    begin
        {err, exp_c_p} = exp_both - 8'd11;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[12:0],11'd0};
        end
    end

    //------------
    else if(abs_c_2[11])
    begin
        {err, exp_c_p} = exp_both - 8'd12;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[11:0],12'd0};
        end
    end

    //------------
    else if(abs_c_2[10])
    begin
        {err, exp_c_p} = exp_both - 8'd13;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[10:0],13'd0};
        end
    end

    //------------
    else if(abs_c_2[9])
    begin
        {err, exp_c_p} = exp_both - 8'd14;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[9:0],14'd0};
        end
    end

    //------------
    else if(abs_c_2[8])
    begin
        {err, exp_c_p} = exp_both - 8'd15;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[8:0],15'd0};
        end
    end

    //------------
    else if(abs_c_2[7])
    begin
        {err, exp_c_p} = exp_both - 8'd16;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[7:0],16'd0};
        end
    end

    //------------
    else if(abs_c_2[6])
    begin
        {err, exp_c_p} = exp_both - 8'd17;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[6:0],17'd0};
        end
    end

    //------------
    else if(abs_c_2[5])
    begin
        {err, exp_c_p} = exp_both - 8'd18;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[5:0],18'd0};
        end
    end

    //------------
    else if(abs_c_2[4])
    begin
        {err, exp_c_p} = exp_both - 8'd19;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[4:0],19'd0};
        end
    end

    //------------
    else if(abs_c_2[3])
    begin
        {err, exp_c_p} = exp_both - 8'd20;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[3:0],20'd0};
        end
    end

    //------------
    else if(abs_c_2[2])
    begin
        {err, exp_c_p} = exp_both - 8'd21;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[2:0],21'd0};
        end
    end

    //------------
    else if(abs_c_2[1])
    begin
        {err, exp_c_p} = exp_both - 8'd22;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[1:0],22'd0};
        end
    end

    //------------
    else if(abs_c_2[0])
    begin
        {err, exp_c_p} = exp_both - 8'd23;

        if (err)
        begin
            exp_c  = 8'd0;
            abs_c  = 24'h000000;
        end
        else
        begin
            exp_c  = exp_c_p;
            abs_c  = {abs_c_2[0],23'd0};
        end
    end

    //------------
    else
    begin
        err       = 1'b0;
        exp_c_p = 8'd0;
        exp_c   = 8'd0;
        abs_c   = 24'h000000;
    end
end

assign c = {sign_c, exp_c, abs_c[22:0]};  // 1bit符号 + 8bit指数 + 23位尾数

endmodule